// +----------------------------------------------------------------------
// | Manong.Cloud [ 领酷码农云 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2020 http://www.manong.cloud All rights reserved.
// +----------------------------------------------------------------------
// | Author: 稻草人 <qinuoyun@qq.com>
// +----------------------------------------------------------------------
// | Member: 围棋 飘逸者 Loumt Silence24
// +----------------------------------------------------------------------

import fs from "fs"

import { Sequelize, Op } from 'sequelize';
import utils from './utils.js';

class database {
    /**
     * 实例对象
     * @type {String}
     */
    sequelize = null

    /**
     * 配置文件
     * @type {Object}
     */
    config = {}

    /**
     * 表格字段
     * @type {Object}
     */
    _tableFields = {}

    /**
     * 扩展说明
     * @type {{"<=": string, ne: string, lt: string, gte: string, eq: string, "<": string, lte: string, "!=": string, "=": string, gt: string, ">": string, ">=": string}}
     * @private
     */
    _exp = {
        "=": Op.eq,
        "eq": Op.eq,
        ">": Op.gt,
        "gt": Op.gt,
        "<": Op.lt,
        "lt": Op.lt,
        ">=": Op.gte,
        "gte": Op.gte,
        "<=": Op.lte,
        "lte": Op.lte,
        "!=": Op.ne,
        "in": Op.in,
        "ne": Op.ne,
        "is": Op.is,
        "not": Op.not,
        "notIn": Op.notIn,
        "or": Op.or,
        "like": Op.like,
        "notLike": Op.notLike,
    }


    operatorsAliases = {
        $eq: Op.eq,
        $ne: Op.ne,
        $gte: Op.gte,
        $gt: Op.gt,
        $lte: Op.lte,
        $lt: Op.lt,
        $not: Op.not,
        $in: Op.in,
        $notIn: Op.notIn,
        $is: Op.is,
        $like: Op.like,
        $notLike: Op.notLike,
        $iLike: Op.iLike,
        $notILike: Op.notILike,
        $regexp: Op.regexp,
        $notRegexp: Op.notRegexp,
        $iRegexp: Op.iRegexp,
        $notIRegexp: Op.notIRegexp,
        $between: Op.between,
        $notBetween: Op.notBetween,
        $overlap: Op.overlap,
        $contains: Op.contains,
        $contained: Op.contained,
        $adjacent: Op.adjacent,
        $strictLeft: Op.strictLeft,
        $strictRight: Op.strictRight,
        $noExtendRight: Op.noExtendRight,
        $noExtendLeft: Op.noExtendLeft,
        $and: Op.and,
        $or: Op.or,
        $any: Op.any,
        $all: Op.all,
        $values: Op.values,
        $col: Op.col
    };


    /**
     * 构造函数
     * @param {[Object]} config对象
     */
    constructor(config) {
        //处理URI链接
        if (config && !this.sequelize && config.hostname) {
            this.config = config;
            this.sequelize = new Sequelize({
                "host": config.hostname,
                "port": config.hostport,
                "username": config.username,
                "password": config.password,
                "database": config.database,
                "dialect": config.dialect,
                "dialectOptions": {
                    "charset": 'utf8mb4',
                    "dateStrings": true,
                    "typeCast": true
                },
                "timezone": '+08:00',
                "logging": function() {

                },
                // "operatorsAliases": this.operatorsAliases
            });
        }
        //判断链接是否生效
        if (this.sequelize) {
            this.automatically();
        }
    }

    transaction() {
        return this.sequelize.transaction();
    }


    /**
     * 自动创建机制
     * @return {[type]} [description]
     */
    automatically() {
        //读取对象目录
        // let modulesDir = ROOT_DIR + DS + "src" + DS + "modules";
        //循环自动创建OMR对象
        for (let item in __modules__) {
            const ModelClass = __modules__[item];
            if (ModelClass && Object.prototype.toString.call(ModelClass) === "[object Function]") {
                let ModelData = new ModelClass();
                if (ModelData.tableFields) {
                    let tableFields = ModelData.tableFields();
                    this.createTable(ModelData.getTableName(), tableFields);
                }
                //销毁对象
                ModelData = null
            }
        }
    }

    /**
     * 遍历目录结构数据
     * @param  {[type]} path     [description]
     * @param  {Array}  fileList [description]
     * @return {[type]}          [description]
     */
    _readDirSync(path, fileList = []) {
        let pa = fs.readdirSync(path);
        pa.forEach((ele, index) => {
            let info = fs.statSync(path + DS + ele)
            if (info.isDirectory()) {
                let _list = this._readDirSync(path + DS + ele);
                fileList = fileList.concat(_list)
            } else {
                if (ele != '.DS_Store') {
                    fileList.push(path + DS + ele);
                }

            }
        })
        return fileList;
    }

    /**
     * 获取字段
     * @return {[type]} [description]
     */
    _getField(table, field = null) {
        if (table) {
            if (field) {
                return this._tableFields[table][field] || false
            }
            return this._tableFields[table] || false
        }
        return false
    }

    /**
     * 创建数据库表
     * @return {[type]} [description]
     */
    createTable(tableName, tableFields) {
        //表格前缀处理
        let tableprefix = this.config.tableprefix || "";
        if (tableprefix.charAt(tableprefix.length - 1) == '_') {
            tableprefix = tableprefix.substr(0, tableprefix.length - 1);
        }
        this._tableFields[tableName] = tableFields;
        //用于数据数据库表结构
        tableFields = this.fieldsORM(tableFields);
        //创建模型
        const Model = this.sequelize.define(tableName, tableFields, {
            // 时间戳
            timestamps: true,
            // 软删除
            paranoid: true,
            // 前缀
            schema: tableprefix,
            // 连字符
            schemaDelimiter: '_',
            // 字段格式
            createdAt: 'created_time',
            updatedAt: 'updated_time',
            deletedAt: 'deleted_time',
            underscored: false,
            //用于处理时间格式化问题，否则返回的时间为国际时间
            dialectOptions: {
                dateStrings: true,
                typeCast: true
            },
            // 禁止修改表名
            // 默认情况下，sequelize 会自动将所有传递的模型名称转换为复数形式。 如果不想这样做，请设置以下内容
            freezeTableName: true,
            //修改表明
            tableName: tableName
        });
        // console.log("Model", Model.getAttribute())
        //用于自动同步创建表结构
        //Model.sync({ alter: true });
    }

    /**
     * 获取数据类型
     * @param  {[type]} type [description]
     * @return {[type]}      [description]
     */
    _getTypeInfo(type) {
        if (type) {
            let typeInfo = type.match(/([\w\W]+)\((.*?)\)/);
            //切割数据类型信息
            if (typeInfo) {
                typeInfo = [typeInfo[1], typeInfo[2]]
            } else {
                typeInfo = [type];
            }
            //匹配返回数据类型
            switch (typeInfo[0].toLowerCase()) {
                case 'int':
                    return typeInfo[1] ? Sequelize.INTEGER(parseInt(typeInfo[1])) : Sequelize.INTEGER;
                    break;
                case 'bigint':
                    return typeInfo[1] ? Sequelize.BIGINT(parseInt(typeInfo[1])) : Sequelize.BIGINT;
                    break;
                case 'varchar':
                    return typeInfo[1] ? Sequelize.STRING(parseInt(typeInfo[1])) : Sequelize.STRING;
                    break;
                case 'text':
                    return Sequelize.TEXT;
                    break;
                case 'json':
                case 'longtext':
                    return Sequelize.TEXT("long");
                    break;
                default:
                    return Sequelize.STRING;
            }
        } else {
            return Sequelize.STRING;
        }
    }

    /**
     * 字段的ORM数据处理
     * @return {[type]} [description]
     */
    fieldsORM(tableFields) {
        let FieldsArray = {};
        for (var key in tableFields) {
            let item = tableFields[key];
            //在原型链上添加方法,用于判断对象上该属性是否存在，存在就返回，否则为空
            Object.defineProperty(item, 'getAttrValue', {
                value(v) {
                    return this.hasOwnProperty(v) ? this[v] : '';
                }
            });
            //初始化字段信息
            let FieldsItem = {};
            //设置参数信息-字段类型
            Object.defineProperty(FieldsItem, 'type', {
                value: this._getTypeInfo(item.type),
                enumerable: true,
                writable: true
            });
            //处理关系形数据库的JSON数据
            if (item.type == "json") {
                FieldsItem['get'] = function(value) {
                    return JSON.parse(this.getDataValue(value));
                }
                FieldsItem['set'] = function(value, key) {
                    this.setDataValue(key, JSON.stringify(value));
                }
            }
            //设置参数信息-默认值
            Object.defineProperty(FieldsItem, 'defaultValue', {
                value: item.getAttrValue('defaultValue') || item.getAttrValue('defaultValue') === 0 ? item.getAttrValue('defaultValue') : null,
                enumerable: true,
                writable: true,
            });
            //设置参数信息-是否设置为主键
            Object.defineProperty(FieldsItem, 'primaryKey', {
                value: item.primaryKey ? true : false,
                enumerable: item.hasOwnProperty("primaryKey"),
                writable: true,
            });
            //设置参数信息-设置设置为自动递增
            Object.defineProperty(FieldsItem, 'autoIncrement', {
                value: item.autoIncrement ? true : false,
                enumerable: item.hasOwnProperty("autoIncrement"),
                writable: true,
            });
            //设置参数信息-设置字段注释
            Object.defineProperty(FieldsItem, 'comment', {
                value: item.getAttrValue('label') + item.getAttrValue('comment'),
                enumerable: true,
                writable: true
            });
            //设置参数信息-设置不能为空
            Object.defineProperty(FieldsItem, 'allowNull', {
                value: item.allowNull ? item.allowNull : true,
                enumerable: true,
                writable: true
            });
            FieldsArray[key] = FieldsItem;
        }
        return FieldsArray;
    }

    /**
     * 设置表名
     * @return {[type]} [description]
     */
    name(name) {
        //初始化请空配置
        this.options = {
            name: name.toLowerCase(),
            where: '',
            order: '',
            fields: '',
            view: {
                join: false,
                include: []
            },
            join: {},
            group: "",
            having: [],
            paranoid: true
        }
        return this;
    }

    /**
     * [user description]
     * @return {[type]} [description]
     */
    user(id = null) {
        this.setUser(id);
        return this;
    }

    /**
     * [user description]
     * @return {[type]} [description]
     */
    group(name = null) {
        this.options['group'] = name;
        return this;
    }

    /**
     * [user description]
     * @return {[type]} [description]
     */
    having(data = null) {
        this.options['having'] = data;
        return this;
    }

    /**
     * [user description]
     * @return {[type]} [description]
     */
    setUser(id = null) {
        let { name } = this.options;
        let fields = this._getField(name);
        if (fields.hasOwnProperty('UID') && id) {
            this.options['user'] = true;
            this.options.where = { "UID": id }
        }
        return this;
    }

    /**
     * 设置字段
     * @return {[type]} [description]
     */
    fields(attributes) {
        this.options['fields'] = attributes;
        return this;
    }

    /**
     * 调用软删除的关联数据
     * @return {[type]} [description]
     */
    paranoid(value = false) {
        this.options['paranoid'] = value ? true : false
        return this;
    }


    /**
     * 查询条件
     * @param  {[type]} field [description]
     * @param  {[type]} op    [description]
     * @param  {[type]} value [description]
     * @return {[type]}       [description]
     */
    where(field, op = null, value = null) {
        if (is_string(field) && is_string(op)) {
            let _where = {};
            let _op = this._exp[op];
            _where[field] = {
                [_op]: value
            }
            field = _where;
        }
        //如果第一个元素为数组，且后面两个元素为空的情况下
        if (Object.prototype.toString.call(field) === "[object Array]" && op == null && value == null) {

        }
        //如果第一个元素为数组，第二个元素为OR的时候
        if (Object.prototype.toString.call(field) === "[object Array]" && op == "or" && value == null) {

        }
        this.options['where'] = field;
        //返回实例本身
        return this;
    }

    /**
     * 纯模型
     */
    raw() {
        this.options['raw'] = true
        return this;
    }

    /**
     * 数据排序
     * @param  {[type]} order [description]
     * @return {[type]}       [description]
     */
    order(order = "", type = 1) {
        this.options['order']
        if (type == 1) {
            this.options['order'] = [order]
        } else {
            this.options['order'] = order
        }
        return this;
    }

    /**
     * 设置数据极限
     * @param  {String} limit [description]
     * @param  {String} end   [description]
     * @return {[type]}       [description]
     * { offset: 5, limit: 5 }
     */
    limit(limit = "", offset = "") {
        //设置参数信息-limit
        Object.defineProperty(this.options, 'limit', {
            value: limit,
            enumerable: limit ? true : false,
            writable: true,
        });
        //设置参数信息-offset
        Object.defineProperty(this.options, 'offset', {
            value: offset,
            enumerable: offset ? true : false,
            writable: true,
        });
        return this;
    }

    /**
     * 用于数据分页
     * @param  {String} page [description]
     * @param  {String} size [description]
     * @return {[type]}      [description]
     * page-number
     * page-size
     * page-total
     * page-count
     */
    page(page = "", size = "") {
        this.options['page'] = true;
        this.options['pageInfo'] = {
            "number": parseInt(page),
            "size": parseInt(size),
            "total": 0,
            "count": 0,
        }
        return this;
    }

    /**
     * 执行SQL语句
     * @param sql
     * @param replacements
     * @returns {Promise<unknown>}
     */
    sql(sql, replacements) {
        return new Promise((resolve, reject) => {
            this.sequelize.query(sql, { replacements: replacements, type: this.sequelize.QueryTypes.SELECT }).then(projects => {
                resolve(projects);
            }).catch(error => {
                reject(error);
            })
        })

    }

    /**
     * 执行数据写入
     * @param  {Object} data [description]
     * @return {[type]}      [description]
     */
    async insert(data = {}, options = {}) {
        try {
            let collect = this.sequelize.models[this.options['name']]
            let returned = await collect.create(data, options);
            return returned.toJSON();
        } catch (error) {
            throw error;
        }
    }

    /**
     * 批量插入
     * @param  {[type]} data [description]
     * @return {[type]}      [description]
     */
    async bulkCreate(data, options = {}) {
        try {
            let collect = this.sequelize.models[this.options['name']]
            const returned = await collect.bulkCreate(data, options);
            return returned;
        } catch (error) {
            throw error;
        }
    }

    /**
     * 删除数据-默认软删除
     * @param  {[type]} data [description]
     * @return {[type]}      [description]
     */
    async delete(options = {}) {
        try {
            let collect = this.sequelize.models[this.options['name']];
            options.where = this.options['where'];
            const returned = await collect.destroy(options);
            return returned;
        } catch (error) {
            throw error;
        }
    }

    /**
     * 真正销毁数据
     * @param  {[type]} data [description]
     * @return {[type]}      [description]
     */
    async destroy(options = {}) {
        try {
            let collect = this.sequelize.models[this.options['name']]
            options.where = this.options['where'];
            options.force = true;
            const returned = await collect.destroy(options)
            return returned;
        } catch (error) {
            throw error;
        }
    }

    /**
     * 清空数据列表
     * @returns {Promise<*>}
     */
    async empty() {
        try {
            let collect = this.sequelize.models[this.options['name']]
            const returned = await collect.destroy({
                where: {},
                force: true
            })
            return returned;
        } catch (error) {
            throw error;
        }
    }

    /**
     * 恢复删除的数据-仅在软删除的下支持
     * @return {[type]} [description]
     */
    async restore(options = {}) {
        try {
            let collect = this.sequelize.models[this.options['name']]
            options.where = this.options['where'];
            const returned = await collect.restore(options)
            return returned;
        } catch (error) {
            throw error;
        }
    }

    /**
     * 更新数据
     * @param  {[type]} data [description]
     * @return {[type]}      [description]
     */
    async update(data, options = {}) {
        try {
            let collect = this.sequelize.models[this.options['name']]
            options.where = this.options['where'];
            const returned = await collect.update(data, options);
            return returned;
        } catch (error) {
            throw error;
        }
    }

    /**
     * 获取Include
     * @returns {*[]}
     */
    getInclude(collect) {
        let include = [];
        //获取关联信息数据
        for (let index in this.options['join']) {
            //获取关联信息数据
            let joinInfo = this.options['join'][index];
            //获取需要的模型数据
            let JoinModel = this.sequelize.models[joinInfo['name']];

            let __include = {
                "model": JoinModel,
                "as": joinInfo['as']
            }
            if (!collect.hasAlias(joinInfo['as'])) {
                let keyInfo = { foreignKey: joinInfo['field'], as: joinInfo['as'] };

                if (joinInfo['relation'] === 'id') {
                    keyInfo['targetKey'] = joinInfo['relation']
                } else {
                    keyInfo['sourceKey'] = joinInfo['relation']
                }

                //targetKey
                if (joinInfo.type === "hasOne") {
                    //设置关联字段
                    collect.hasOne(JoinModel, keyInfo)
                }

                if (joinInfo.type === "belongsTo") {
                    //设置关联字段
                    collect.belongsTo(JoinModel, keyInfo);
                }

                if (joinInfo.type === "hasMany") {
                    //设置关联字段
                    collect.hasMany(JoinModel, keyInfo)
                }
            }

            if (joinInfo['include']) {
                let includeInfo = joinInfo['include'];
                //获取需要的模型数据
                let includeModel = this.sequelize.models[includeInfo['name']];
                if (!JoinModel.hasAlias(includeInfo['as'])) {
                    let includeKeyInfo = { foreignKey: includeInfo['field'], as: includeInfo['as'] };

                    if (includeInfo['relation'] === 'id') {
                        includeKeyInfo['targetKey'] = includeInfo['relation']
                    } else {
                        includeKeyInfo['sourceKey'] = includeInfo['relation']
                    }

                    //targetKey
                    if (includeInfo.type === "hasOne") {
                        //设置关联字段
                        JoinModel.hasOne(includeModel, includeKeyInfo)
                    }

                    if (includeInfo.type === "belongsTo") {
                        //设置关联字段
                        JoinModel.belongsTo(includeModel, includeKeyInfo);
                    }

                    if (includeInfo.type === "hasMany") {
                        //设置关联字段
                        JoinModel.hasMany(includeModel, includeKeyInfo)
                    }
                }

                __include['include'] = [{
                    'model': includeModel,
                    'as': includeInfo['as'],
                    'where': includeInfo['where'],
                    'attributes': includeInfo['attributes']
                }]

            }

            //处理where条件
            if (joinInfo.where) {
                __include['where'] = joinInfo.where
            }
            //设置获取字段
            if (joinInfo.attributes && joinInfo.attributes.length) {
                __include['attributes'] = joinInfo.attributes;
            }
            //处理关联数据
            include.push(__include);
        }
        return include;
    }

    /**
     * 查询多条
     * @param isSql 为true 时 执行高速查询
     * @returns {Promise<*>}
     */
    async select(isSql = false, options = {}) {
        try {
            let collect = this.sequelize.models[this.options['name']]

            Object.defineProperty(options, 'order', {
                value: this.options['order'],
                enumerable: this.options['order'] ? true : false,
                writable: true,
            });

            Object.defineProperty(options, 'where', {
                value: this.options['where'],
                enumerable: this.options['where'] ? true : false,
                writable: true,
            });

            Object.defineProperty(options, 'limit', {
                value: this.options['limit'],
                enumerable: this.options['limit'] ? true : false,
                writable: true,
            });

            Object.defineProperty(options, 'offset', {
                value: this.options['offset'],
                enumerable: this.options['offset'] ? true : false,
                writable: true,
            });

            Object.defineProperty(options, 'group', {
                value: this.options['group'],
                enumerable: this.options['group'] ? true : false,
                writable: true,
            });

            Object.defineProperty(options, 'having', {
                value: this.options['having'],
                enumerable: this.options['having'].langth ? true : false,
                writable: true,
            });

            Object.defineProperty(options, 'paranoid', {
                value: this.options['paranoid'],
                enumerable: this.hasOwnProperty("paranoid"),
                writable: true,
            });


            //处理关联查询用的
            if (this.options['join']) {
                options['include'] = this.getInclude(collect)
            }

            //判断是否需要进行数据分页
            //这里可能存在数据阻隔问题
            if (this.options['page']) {
                //如果该字段存在，需要删除，避免错乱
                if (options['limit']) delete options['limit'];
                if (options['offset']) delete options['offset'];
                let { pageInfo } = this.options;

                options = Object.assign({ distinct: true }, options)
                //返回总的条数
                const pageObject = await collect.findAndCountAll(options);
                if (pageObject) {
                    pageInfo.total = pageObject.count;
                }

                //获取分多少页
                pageInfo.count = Math.ceil(pageInfo.total / pageInfo.size);
                //设置页码和偏移量
                options['limit'] = parseInt(pageInfo.size);
                options['offset'] = parseInt(pageInfo.size) * parseInt(pageInfo.number - 1);

            }

            //处理字段
            if (this.options['fields']) {
                options['attributes'] = this.options['fields'];
            }

            //处理数据返回的结构
            if (this.options['view'] && this.options['view']['join']) {
                options = this._getViewOptions(options)
            }
            /**
             * 初始化返回值
             * @type {*[]}
             */
            let returned = [];
            if (isSql) {
                let querySql = utils.genSqlString.apply(collect, [collect, options])
                returned = await this.sql(querySql);
            } else {
                returned = await collect.findAll(options);
            }

            if (returned) {
                if (this.options.hasOwnProperty("pageInfo")) {
                    return {
                        ...this.options.pageInfo,
                        children: returned
                    }
                } else {
                    return returned;
                }
            } else {
                return [];
            }
        } catch (error) {
            throw error;
        }
    }

    /**
     * 查询单条
     * @param isSql 为true 时 执行高速查询
     * @returns {Promise<*>}
     */
    async first(isSql = false) {
        try {
            let collect = this.sequelize.models[this.options['name']];
            let options = {};

            Object.defineProperty(options, 'where', {
                value: this.options['where'],
                enumerable: this.options['where'] ? true : false,
                writable: true,
            });

            Object.defineProperty(options, 'order', {
                value: this.options['order'],
                enumerable: this.options['order'] ? true : false,
                writable: true,
            });

            Object.defineProperty(options, 'paranoid', {
                value: this.options['paranoid'],
                enumerable: this.hasOwnProperty("paranoid"),
                writable: true,
            });

            if (this.options['join']) {
                options['include'] = this.getInclude(collect)
            }

            //处理字段
            if (this.options['fields']) {
                options['attributes'] = this.options['fields'];
            }

            //处理关联数据结构
            if (this.options['view'] && this.options['view']['join']) {
                options = this._getViewOptions(options)
            }

            let returned = "";
            if (isSql) {
                let querySql = utils.genSqlString.apply(collect, [collect, options])
                returned = await this.sql(querySql);
                if (returned.length) {
                    returned = returned[0];
                }
            } else {
                returned = await collect.findOne(options);
                if (returned) {
                    returned = returned.toJSON();
                }
            }
            return returned;
        } catch (error) {
            throw error;
        }
    }

    /**
     * 处理试图关联查询
     * @param  {[type]}  join  [description]
     * @param  {Boolean} field [description]
     * @param  {[type]}  on    [description]
     * @param  {String}  type  [description]
     * @return {[type]}        [description]
     */
    view(join, field = '', on = null, type = 'INNER') {
        // this.options['view'] = true;
        // this.options['join'] = {
        //     name: join
        //     id: field
        // }
        return this;
    }

    /**
     * 获取Join表名及别名 支持
     * @param  {[type]} join  [description]
     * @param  {[type]} alias [description]
     * @return {[type]}       [description]
     */
    getJoinTable(join, alias = null) {

    }

    /**
     * 查询SQL组装 join
     * @access public
     * @param mixed  $join      关联的表名
     * @param mixed  $condition 条件
     * @param string $type      JOIN类型
     * @return $this
     */
    join($join, $condition = null, $type = 'INNER') {

    }

    /**
     * 获取模型
     * @param name
     * @returns {*}
     */
    getModel(name = '') {
        return this.sequelize.models[name || this.options['name']];
    }

    /**
     * 判断模型是否存在
     * @param name
     * @returns {boolean}
     */
    isModel(name) {
        return this.sequelize.models[name] ? true : false;
    }

    /**
     * 模型列表
     * @returns {*}
     */
    getModels() {
        return this.sequelize.models;
    }

    /**
     * 模型列表
     * @returns {*}
     */
    getRaw() {
        return this.sequelize;
    }

    _getViewOptions(options) {
        options.include = this.options['view']['include'];
        return options;
    }

    _join(target, foreignKey, sourceKey) {
        let collect = this.sequelize.models[this.options['name']];
        collect.hasOne(target, { foreignKey, sourceKey });
    }


    leftJoin(model, foreignKey, sourceKey, attribute = {}, where = {}) {
        model = model.toLowerCase();
        let target = this.sequelize.models[model];
        this.options['join'] = false;
        this.options['view'].include.push({
            where: where,
            right: false,
            model: target,
            required: false
        })
        this.options['view'].join = true;
        this._join(target, foreignKey, sourceKey);
        return this;
    }

    rightJoin(model, foreignKey, sourceKey, attribute = {}, where = {}) {
        model = model.toLowerCase();
        let target = this.sequelize.models[model];
        this.options['join'] = false;
        this.options['view'].include.push({
            attribute: attribute,
            where: where,
            right: true,
            model: target,
            required: false
        })
        this.options['view'].join = true;
        this._join(target, foreignKey, sourceKey);
        return this;
    }

    innerJoin(model, foreignKey, sourceKey, attribute = {}, where = {}) {
        model = model.toLowerCase();
        let target = this.sequelize.models[model];
        this.options['join'] = false;
        this.options['view'].include.push({
            where: where,
            right: false,
            model: target,
            required: true
        })
        this.options['view'].join = true;
        this._join(target, foreignKey, sourceKey);
        return this;
    }


}

class sql {
    /**
     * 数据库连接实例
     * @type {Array}
     */
    static instance = [];

    /**
     * 数据库初始化，并取得数据库类实例
     * @access public
     * @param  mixed       config 连接配置
     * @param  bool|string name   连接标识 true 强制重新连接
     * @return Connection
     * @throws Exception
     */
    static connect(config = [], name = false) {
        if (false === name) {
            name = md5(to_json(config));
        }
        if (true === name || !isset(this.instance[name])) {
            let options = config;
            this.instance[name] = new database(options);
        }
        return this.instance[name];
    }
}

export default sql;
